#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import shutil
import tempfile

import codecs
import os
import sys

execfile(os.path.join(sys.path[0], "framework.py"))

from oriolus.docker.storages.filestorage import FileStorage, FilePacketEntryReader
from oriolus.pith.packets.meta import Meta
from oriolus.pith.packets.script import Script
from oriolus.pith.packets.packet import FilePacket, Packet, Status
from unittest import TestCase, TestLoader, TextTestRunner

class TestFileStorage(TestCase):
    def setUp(self):
        self.__empty_storage_path = os.path.abspath("./test_empty_storage")
        self.__test_storage_path2 = os.path.abspath("./test_storage2")
        self.__temp_dirs = [self.__empty_storage_path, self.__test_storage_path2]
        if not os.path.exists(self.__test_storage_path2):
            os.mkdir(self.__test_storage_path2)

    def tearDown(self):
        map(self.__clear_path, self.__temp_dirs)

    def __clear_path(self, path):
        if os.path.exists(path):
            shutil.rmtree(path)

    def test_absent_storage(self):
        FileStorage(self.__empty_storage_path)
        self.assertTrue(os.path.exists(self.__empty_storage_path))

    def test_existing_storage(self):
        self.assertTrue(os.path.exists(self.__test_storage_path2))
        FileStorage(self.__test_storage_path2)

    # consistency     
    def test_serialization_consistency(self):
        test_packet = FilePacket("./testdata/testpackets/test_packet-1.2.3.4.zip.ori", "some_base_path")
        storage = FileStorage(self.__test_storage_path2)
        entry = storage.add(test_packet)
        self.assertEqual(1, len(storage.entries))
        self.assertEqual(entry.basepath, storage.entries[0].basepath)
        self.assertEqual(entry.name, storage.entries[0].name)
        self.assertEqual(entry.status, storage.entries[0].status)

    def test_add(self):
        base_dir = tempfile.mkdtemp()
        
        try:
            test_packet = FilePacket("./testdata/testpackets/test_packet-1.2.3.4.zip.ori", base_dir)
            storage = FileStorage(self.__test_storage_path2)
            packet_entry = storage.add(test_packet)
            expected_entry_name = "test_packet-1.2.3.4.ori.entry"
            script_names = ("install", "postinstall", "postremove", "preinstall", "preremove", "remove")
            script_name_builder = lambda x: x + ".py"
            packet_script_path_builder = lambda x: os.path.join(self.__test_storage_path2, "test_packet-1.2.3.4", x + ".py")
            
            expected_file_names = []
            map(lambda x: expected_file_names.append(script_name_builder(x)), script_names)
            
            self.assertTrue(os.path.exists(os.path.join(self.__test_storage_path2, expected_entry_name)))
            self.assertTrue(os.path.exists(os.path.join(self.__test_storage_path2, "test_packet-1.2.3.4")))
            
            for expected_file_name in expected_file_names:
                self.assertTrue(os.path.exists(os.path.join(self.__test_storage_path2, "test_packet-1.2.3.4", expected_file_name)))
    
            expected_file_packet = Packet(Meta("test_packet", "1.2.3.4", "Test packet", [], [], []), status=Status.NEW)
            actual_file_packet = FilePacketEntryReader().read(os.path.join(self.__test_storage_path2, "test_packet-1.2.3.4.ori.entry"))
            self.__assertFilePacketEntryEqual(expected_file_packet, actual_file_packet)
    
            expected_install_script_content = ""
            expected_install_script_path = packet_script_path_builder("install")
            actual_install_script_content = file(expected_install_script_path).read()
            self.assertEqual(expected_install_script_content, actual_install_script_content)
    
            expected_postinstall_script_content = ""
            expected_postinstall_script_path = packet_script_path_builder("postinstall")
            actual_postinstall_script_content = file(expected_postinstall_script_path).read()
            self.assertEqual(expected_postinstall_script_content, actual_postinstall_script_content)
    
            expected_postremove_script_content = ""
            expected_postremove_script_path = packet_script_path_builder("postremove")
            actual_postremove_script_content = file(expected_postremove_script_path).read()
            self.assertEqual(expected_postremove_script_content, actual_postremove_script_content)
    
            expected_preremove_script_content = ""
            expected_preremove_script_path = packet_script_path_builder("preremove")
            actual_preremove_script_content = file(expected_preremove_script_path).read()
            self.assertEqual(expected_preremove_script_content, actual_preremove_script_content)
    
            expected_remove_script_content = ""
            expected_remove_script_path = packet_script_path_builder("remove")
            actual_remove_script_content = file(expected_remove_script_path).read()
            self.assertEqual(expected_remove_script_content, actual_remove_script_content)
                            
            expected_preinstall_script_content = "import os\r\n\r\nprint \"Test\""
            expected_preinstall_script_path = os.path.join(self.__test_storage_path2, "test_packet-1.2.3.4", "preinstall.py")
            actual_preinstall_script_content = codecs.open(expected_preinstall_script_path, encoding = "utf-8").read()
            self.assertEqual(expected_preinstall_script_content, actual_preinstall_script_content) 
            
            self.assertEqual(packet_entry.name, test_packet.name)
            self.assertEqual(packet_entry.status, test_packet.status)
            self.assertEqual(packet_entry.meta, test_packet.meta)
            self.assertEqual(packet_entry.basepath, test_packet.basepath)
            self.assertEqual(packet_entry.basepath, base_dir)
            
            expected_scripts = []
            map(lambda x: expected_scripts.append(Script(x, packet_script_path_builder(x))), script_names)
            
            [self.assertEqual(script.path, packet_script_path_builder(script.name)) for script in packet_entry.scripts]
            
        finally:
            shutil.rmtree(base_dir)
     

    def test_remove(self):
        test_packet = FilePacket("./testdata/testpackets/test_packet-1.2.3.4.zip.ori")
        storage = FileStorage(self.__test_storage_path2)
        storage.add(test_packet)
        expected_entry_name = "test_packet-1.2.3.4.ori.entry"
        expected_file_names = ("install.py", "postinstall.py", "postremove.py", 
                               "preinstall.py", "preremove.py", "remove.py")
        
        self.assertTrue(os.path.exists(os.path.join(self.__test_storage_path2, expected_entry_name)))
        self.assertTrue(os.path.exists(os.path.join(self.__test_storage_path2, "test_packet-1.2.3.4")))
        
        for expected_file_name in expected_file_names:
            self.assertTrue(os.path.exists(os.path.join(self.__test_storage_path2, "test_packet-1.2.3.4", expected_file_name)))

        storage.remove("test_packet-1.2.3.4")

        self.assertFalse(os.path.exists(os.path.join(self.__test_storage_path2, expected_entry_name)))
        for expected_file_name in expected_file_names:
            self.assertFalse(os.path.exists(os.path.join(self.__test_storage_path2, "test_packet-1.2.3.4", expected_file_name)))

        self.assertFalse(os.listdir(self.__test_storage_path2))

    def test_entries(self):
        test_packet = FilePacket("./testdata/testpackets/test_packet-1.2.3.4.zip.ori")
        storage = FileStorage(self.__test_storage_path2)
        storage.add(test_packet)
        
        actual_entries = storage.entries
        self.assertEqual(1, len(actual_entries))
        actual_packet = actual_entries[0]

        self.assertEqual(test_packet.name, actual_packet.name)
        self.assertEqual(test_packet.meta.version, actual_packet.meta.version)
        self.assertEqual(test_packet.meta.description, actual_packet.meta.description)
        self.assertEqual([], actual_packet.meta.conflicts)
        self.assertEqual([], actual_packet.meta.depends)
        self.assertEqual([], actual_packet.meta.replaces)
        
        self.assertEqual(6, len(actual_packet.scripts))
        self.assertTrue("install" in [script.name for script in actual_packet.scripts])
        self.assertEqual(test_packet.status, actual_packet.status)

    def __assertFilePacketEntryEqual(self, expected, actual):
        self.assertEqual(type(expected), type(actual))
        self.assertEqual(expected.meta.name, actual.meta.name)
        self.assertEqual(expected.meta.version, actual.meta.version)
        self.assertEqual(expected.meta.description, actual.meta.description)
        self.assertEqual(expected.meta.conflicts, actual.meta.conflicts)
        self.assertEqual(expected.meta.replaces, actual.meta.replaces)
        self.assertEqual(expected.meta.depends, actual.meta.depends)
        self.assertEqual(expected.status, actual.status)

if __name__ == "__main__":
    suite = TestLoader().loadTestsFromTestCase(TestFileStorage)
    TextTestRunner(verbosity=2).run(suite)
